/*
 * File:   Graph.h
 * Author: Elevator
 *
 * Created on 13 Май 2013 г., 21:33
 */

#ifndef GRAPH_H
#define GRAPH_H

#include <map>
#include "Common/Exceptions/NotFoundException.h"


template<typename T>
class Graph
{
private:
	typedef std::map<const T, bool > RowMap;
	typedef std::map<const T, RowMap* > TableMap;

	TableMap _table;
	Vector<T> _nodes;

public:

	void AddNode( const T& node )
	{
		if ( ContainsNode( node ) )
			throw NotFoundException("Node not found");

		RowMap* newRow = new RowMap( );

		for( IteratorPtr<T> nodes( _nodes.GetIterator() );
				!nodes->IsEnd( );
				nodes->Next( ) )
		{
			T item = nodes->Current( );
			RowMap* row = _table[item];
			( *row )[node] = false;
			( *newRow )[item] = false;
		}

		( *newRow )[node] = false;
		_table[node] = newRow;
		_nodes.Add( node );
	}

	void RemoveNode( const T& node )
	{
		if ( !ContainsNode( node ) )
			throw NotFoundException("Node not found");

		for( IteratorPtr<T> nodes( _nodes.GetIterator() );
				!nodes->IsEnd( );
				nodes->Next( ) )
		{
			T item = nodes->Current( );
			_table[item]->erase( node );
		}

		_table.erase( node );
		_nodes.Remove( node );
	}

	bool ContainsNode( const T& node )
	{
		return _nodes.Contains( node );
	}

	bool IsLinked( const T& nodeA, const T& nodeB )
	{
		if ( !ContainsNode( nodeA ) || !ContainsNode( nodeB ) )
			throw NotFoundException("Node not found to check link");

		return _table.at( nodeA )->at( nodeB );
	}

	void SetLinked( const T& nodeA, const T& nodeB, bool linked )
	{
		if ( !ContainsNode( nodeA ) || !ContainsNode( nodeB ) )
			throw NotFoundException("Node not found to set link");

		_table.at( nodeA )->at( nodeB ) = linked;
		_table.at( nodeB )->at( nodeA ) = linked;
	}

	const ICollection<T>* GetNodes( ) const
	{
		return &_nodes;
	}

	const ICollection<T>* GetNeihgbors( T& node )
	{
		if ( !ContainsNode( node ) )
			throw NotFoundException("Node not found to find neighbor");

		Vector<T>* neighbors = new Vector<T > ( );
		RowMap* row = _table[node];

		for( IteratorPtr<T> nodes( _nodes.GetIterator() );
				!nodes->IsEnd( );
				nodes->Next( ) )
		{
			T item = nodes->Current( );
			if ( row->at( item ) )
				neighbors->Add( item );
		}
		return neighbors;
	}
};

#endif  /* GRAPH_H */
